package com.mbc.common.manager;

import java.sql.SQLException;
import java.util.List;

import javax.persistence.NoResultException;

import com.mbc.common.CommonConstants;
import com.mbc.common.CommonConstants.RecordStatus;
import com.mbc.common.data.UserDataList;
import com.mbc.common.entities.User;
import com.mbc.common.entities.UserInBranches;
import com.mbc.common.entities.UserInRoles;
import com.mbc.common.exception.DataDuplicationException;
import com.mbc.common.exception.ForeignConflictException;
import com.mbc.common.exception.UnauthorizedAccessException;
import com.mbc.common.param.CriteriaParams;
import com.mbc.common.utils.KeyGenerator;

public class UserMgr extends AbstractMgr {
	
	public static final byte USER_ONLINE = 2;
	
	public UserMgr()
	{}
	
	public UserMgr(String sessionId)
	{
		this.sessionId = sessionId;
	}
	
	public void resetPassword(long userId, String oldPassword, String newPassword)throws Exception{
		openConnection();
		try {
			beginTransaction();
			User l_User = entityManager.find(User.class, userId);
			if(l_User.getPassword().equals(oldPassword)){
				l_User.setPassword(newPassword);
				entityManager.merge(l_User);
			}
			else
				throw new UnauthorizedAccessException("Password does not match.");
			commitTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			throw e;
		} finally{
			closeConnection();
		}
	}
	
	public void createUser(User user) throws Exception
	{
		openConnection();
		try {
			beginTransaction();
			user.setStatus(RecordStatus.active);
			user.setUserId(KeyGenerator.generateKey(entityManager));
			
			entityManager.persist(user);
			
			for (UserInBranches l_UserInOffices : user.getUserInOfficeList()) {
				l_UserInOffices.setUserId(user.getUserId());
				entityManager.persist(l_UserInOffices);
			}
			
			
			for (UserInRoles l_UserInRoles : user.getUserInRolesList()) {
				l_UserInRoles.setUserId(user.getUserId());
				entityManager.persist(l_UserInRoles);
			}
			commitTransaction();
		} catch (SQLException e) {
			rollbackTransaction();
			if(DataDuplicationException.isUniqueKyeError(e))
				throw new DataDuplicationException(e.getMessage());
			else
				throw e;
		}
		finally
		{
			closeConnection();
		}
	}
	
	public void updateUser(User user, String updatedBy)throws Exception
	{
		openConnection();
		try {
			beginTransaction();
			
			entityManager.merge(user);
			
			entityManager.createNamedQuery("UserInRoles.deleteByUserId")
				.setParameter("userId", user.getUserId())
				.executeUpdate();
			entityManager.createNamedQuery("UserInBranches.deleteByUserId")
				.setParameter("userId", user.getUserId())
				.executeUpdate();
			
			for (UserInBranches l_UserInOffices : user.getUserInOfficeList()) {
				l_UserInOffices.setUserId(user.getUserId());
				entityManager.persist(l_UserInOffices);
			}
			
			for (UserInRoles l_UserInRoles : user.getUserInRolesList()) {
				l_UserInRoles.setUserId(user.getUserId());
				entityManager.persist(l_UserInRoles);
			}
			commitTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			throw e;
		}
		finally{
			closeConnection();
		}
	}
	
	public void deleteUser(long userId)throws Exception{
		openConnection();
		try {
			beginTransaction();
			entityManager.createNamedQuery("UserInRoles.deleteByUserId")
			.setParameter("userId", userId)
			.executeUpdate();
		entityManager.createNamedQuery("UserInBranches.deleteByUserId")
			.setParameter("userId", userId)
			.executeUpdate();
			User l_user = entityManager.find(User.class, userId);
			entityManager.remove(l_user);
			commitTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			if(e.getCause().getCause().getCause() instanceof SQLException){
				if(ForeignConflictException.FOREIGN_CONFLICT_ERROR_CODE == ((SQLException)e.getCause().getCause().getCause()).getErrorCode())
					throw new ForeignConflictException(e);
				else
					throw e;
			}
			else
				throw e;
		}
		finally{
			closeConnection();
		}
	}
	
	public UserDataList getUserList(CriteriaParams cri)throws Exception{
		openConnection();
		try {
            String l_cri = " where u.userName like '%" + cri.getKeyword() + "%' or u.loginId like '%" + cri.getKeyword() + "%'";
            
            String l_searchJPQL = "select u from User u" + l_cri;
            

            List<User> l_entityList = entityManager.createQuery(l_searchJPQL, User.class)
                    .setFirstResult(cri.getIndex())
                    .setMaxResults(cri.getSize())
                    .getResultList();
            
            UserDataList l_dataList = new UserDataList();
            l_dataList.setEntityList(l_entityList);
            
            if(cri.getIndex() == 0){
            	String l_countQuery = "select count(u.userId) from User u" + l_cri;
            	l_dataList.setTotalRecord(entityManager.createQuery(l_countQuery, Long.class).getSingleResult());
            }
			return l_dataList;
		} catch (Exception e) {
			throw e;
		} finally{
			closeConnection();
		}
	}
	
	public User getUser(long userId) throws Exception{
		openConnection();
		try {
			User l_User = entityManager.find(User.class, userId);
			if(l_User != null)
			{
				l_User.setUserInRolesList(entityManager.createNamedQuery("UserInRoles.findByUserId", UserInRoles.class)
						.setParameter("userId", userId)
						.getResultList());
				l_User.setUserInOfficeList(entityManager.createNamedQuery("UserInBranches.findByUserId", UserInBranches.class)
						.setParameter("userId", userId)
						.getResultList());
			}
			return l_User;
		} catch (Exception e) {
			throw e;
		} finally {
			closeConnection();
		}
	}
	
	public User getUser(String loginId)throws Exception{
		openConnection();
		try {
			User l_User = null; 
			try {
				l_User = entityManager.createNamedQuery("User.findByLoginId", User.class)
						.setParameter("loginId", loginId)
						.getSingleResult();
			} catch (NoResultException ex) {
				return null;
			}
			if(l_User != null)
			{
				l_User.setUserInRolesList(entityManager.createNamedQuery("UserInRoles.findByUserId", UserInRoles.class)
						.setParameter("userId", l_User.getUserId())
						.getResultList());
				l_User.setUserInOfficeList(entityManager.createNamedQuery("UserInBranches.findByUserId", UserInBranches.class)
						.setParameter("userId", l_User.getUserId())
						.getResultList());
			}
			return l_User;
		} catch (Exception e) {
			throw e;
		} finally {
			closeConnection();
		}
	}
	
	public void updateUserOnlineStatus(long userId, boolean isOnline)throws Exception{
		openConnection();
		try {
			beginTransaction();
			User l_user = entityManager.find(User.class, userId);
			if(isOnline){
				l_user.setStatus(USER_ONLINE);
			}
			else{
				l_user.setStatus(CommonConstants.RecordStatus.active);
			}
			entityManager.merge(l_user);
			commitTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			throw e;
		} finally {
			closeConnection();
		}
	}
}
